using System;
using System.Collections.Generic;
using SharpObjects.Configuration;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.EventBus;
using SharpObjects.Instantiation.Services;
using SharpObjects.Interfaces;
using SharpObjects.Shared;
using SharpObjects.Shared.ApplicationEvents;

namespace SharpObjects.Logging
{
    public class Log : ILog, IXmlInitializable, IDisposable
    {
        public static readonly Queue<string> ErrorMessages = new Queue<string>();
        public static int MaxErrorQueueSize = 1000;

        public static void AddErrorMessage(string message)
        {
            lock (ErrorMessages)
            {
                ErrorMessages.Enqueue(message);

                if (ErrorMessages.Count > MaxErrorQueueSize)
                {
                    ErrorMessages.Dequeue();
                }
            }
        }

        public static void AddErrorMessage(Exception exception)
        {
            lock (ErrorMessages)
            {
                ErrorMessages.Enqueue(exception.Message + "\n" + exception.StackTrace);

                if (ErrorMessages.Count > MaxErrorQueueSize)
                {
                    ErrorMessages.Dequeue();
                }
            }
        }

        //******************** INSTANCE MEMBERS ************************
        private IEventBus eventBus = null;
        private Dictionary<string, ILogCategory> logCategories = new Dictionary<string, ILogCategory>();

        #region ILog Members

        public bool IsEnabled { get; set; }

        public void Write(LogCategoryName categoryName, Shared.Origin origin, string message, params object[] messageArgs)
        {
            this.logCategories[categoryName].Write(origin, message, messageArgs);
        }

        public void Write(LogCategoryName categoryName, Shared.Origin origin, Exception ex, bool appendStackTrace = true)
        {
            this.logCategories[categoryName].Write(origin, ex, appendStackTrace);
        }

        #endregion

        #region IXmlInitializable Members

        public void Initialize(System.Xml.XmlElement initializationElement)
        {
            IConfigurationProvider init = new XmlConfigurationProvider(initializationElement);

            this.IsEnabled = init.GetBoolean("@is_enabled", init.GetBoolean("is_enabled", true));
            string eventBusId = init.GetString("event_bus_id", null);

            if(eventBusId != null)
            {
                this.eventBus = ServiceFactory.Instance.GetService<IEventBus>(eventBusId);
            }

            string[] logCategoryIds = init.GetStrings("log_category_id");

            foreach (string logCategoryId in logCategoryIds)
            {
                ILogCategory logCategory = ServiceFactory.Instance.GetService<ILogCategory>(logCategoryId);
                this.logCategories.Add(logCategoryId, logCategory);
            }

            this.IsInitialized = true;
        }


        private bool isInitialized = false;

        public bool IsInitialized
        {
            get
            {
                lock (this)
                {
                    return this.isInitialized;
                }
            }
            set
            {
                lock (this)
                {
                    this.isInitialized = value;
                }
            }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (this.isInitialized)
            {

                this.isInitialized = false;
            }
        }

        #endregion
    }
}